package com.itita.ww2.game.user;

import java.util.HashMap;
import java.util.Map;

import org.apache.commons.lang.StringUtils;

import com.google.gson.JsonObject;
import com.itita.ww2.core.MessageHandler;
import com.itita.ww2.data.MissionConfig;
import com.itita.ww2.data.PlayerConfig;
import com.itita.ww2.data.shop.PaymentConfig;
import com.itita.ww2.data.shop.PaymentConfig.Category;
import com.itita.ww2.enums.PushCode;
import com.itita.ww2.game.user.UserInfo.IUserLevelListener;
import com.itita.ww2.game.user.UserRewardDispatch.IUserRewardListener;
import com.itita.ww2.game.user.UserRewardDispatch.RewardType;
import com.itita.ww2.model.CodeType;
import com.itita.ww2.model.building.BDResource;
import com.itita.ww2.model.enums.ResourceType;
import com.itita.ww2.model.user.UserProfile;
import com.itita.ww2.redis.RedisUtil;
import com.itita.ww2.redis.cache.Table;
import com.itita.ww2.utils.DataUtil;
import com.smartfoxserver.v2.entities.data.ISFSObject;
import com.smartfoxserver.v2.entities.data.SFSObject;

/**
 * 用户资源
 * @author NorthLan
 *
 */
public class UserResource implements IUserLevelListener {
	private int uid;
	private UserProfile userProfile;
	// 
	private long oil = 0;
	private long steel = 0;
	private long elec = 0;
	private long cash = 0;
	private long gold = 0;
	private Map<String, Long> resourceMaxMap; // 最大资源量

	public UserResource(UserProfile userProfile) {
		this.userProfile = userProfile;
		this.uid = userProfile.getUid();
	}

	/**
	 * 带检查的资源操作(如果超出最大值,则不做修改)
	 */
	public void operResWithCheck(String code, long value) {
		operResWithCheck(ResourceType.codeValueOf(code), value);
	}

	/**
	 * 带检查的资源操作(如果超出最大值,则不做修改)
	 */
	public void operResWithCheck(ResourceType type, long value) {
		long userRes = getResByType(type);
		userRes += value;
		if (userRes < 0) {
			userRes = 0;
		}
		if (value < 0 || userRes < this.resourceMaxMap.get(type.getValue())) {
			setResByType(type, userRes);
		}
	}

	/**
	 * 操作用户资源(多项)
	 */
	public void operResWithMaxCheck(ISFSObject data, boolean additive) {
		for (String key : data.getKeys()) {
			if (additive) {
				operResWithCheck(key, data.getInt(key));
			} else {
				operResWithCheck(key, -data.getInt(key));
			}
		}
	}

	/**
	 * 用户资源操作
	 */
	public void operRes(String code, long value) {
		operRes(ResourceType.codeValueOf(code), value);
	}

	/**
	 * 用户资源操作
	 */
	public void operRes(ResourceType type, long value) {
		long val = getResByType(type);
		val += value;
		if (val < 0) {
			val = 0;
		}
		setResByType(type, val);
	}

	/**
	 * 用户资源是否足够消耗(单项)
	 */
	public boolean isResEnoughSingle(String code, long value) {
		return getResByType(ResourceType.codeValueOf(code)) >= value;
	}

	/**
	 * 用户资源是否足够消耗(单项)
	 */
	public boolean isResEnoughSingle(ResourceType type, long value) {
		return getResByType(type) >= value;
	}

	/**
	 * 用户资源是否足够消耗(SFSObjecet)
	 */
	public boolean isResEnoughMulti(ISFSObject data) {
		for (String key : data.getKeys()) {
			if (!isResEnoughSingle(key, data.getInt(key))) {
				return false;
			}
		}
		return true;
	}

	/**
	 * 设置资源
	 */
	private void setResByType(ResourceType type, long val) {
		switch (type) {
		case OIL:
			this.oil = val;
			break;
		case CASH:
			this.cash = val;
			break;
		case ELEC:
			this.elec = val;
			break;
		case GOLD:
			this.gold = val;
			break;
		case STEEL:
			this.steel = val;
			break;
		}
	}

	/**
	 * 获取资源
	 */
	public long getResByType(ResourceType type) {
		long ret = 0;
		switch (type) {
		case OIL:
			ret = this.oil;
			break;
		case CASH:
			ret = this.cash;
			break;
		case ELEC:
			ret = this.elec;
			break;
		case GOLD:
			ret = this.gold;
			break;
		case STEEL:
			ret = this.steel;
			break;
		}
		return ret;
	}

	/**
	 * 更新资源最大值
	 */
	private void updateResourceMax(int level) {
		this.resourceMaxMap = PlayerConfig.getMaxResourceMap(level);
	}

	/**
	 * 收集建筑资源<br>
	 * 更新
	 */
	public int collectBDResource() {
		int next = PlayerConfig.getResHarvestDuration();
		for (BDResource bdResource : userProfile.getBDManager().getAllResBuilding()) {
			next = bdResource.collectResource();
		}
		this.update();
		return next;
	}

	/**
	 * 同步资源<br>
	 * 同时更新到redis
	 */
	public synchronized void sync() {
		ISFSObject dataObj = SFSObject.newInstance();
		for (ResourceType res : ResourceType.values()) {
			dataObj.putLong(res.getValue(), getResByType(res));
		}
		ISFSObject pushObj = SFSObject.newInstance();
		pushObj.putSFSObject("data", dataObj);
		MessageHandler.getInstance().pushUser(PushCode.RES, pushObj, userProfile.getSFSUser());
	}

	/**
	 * 加载资源
	 */
	public synchronized void load() {
		Table t = UserService.getInstance().getCacheUserDataTable();
		ISFSObject resObj = DataUtil.objValueOf(t.getValue(RedisUtil.genericKey(this.uid), "resource"));
		this.oil = resObj.getLong(ResourceType.OIL.getValue());
		this.steel = resObj.getLong(ResourceType.STEEL.getValue());
		this.elec = resObj.getLong(ResourceType.ELEC.getValue());
		this.cash = resObj.getLong(ResourceType.CASH.getValue());
		this.gold = resObj.getLong(ResourceType.GOLD.getValue());
	}

	/**
	 * 更新资源
	 */
	public synchronized void update() {
		// 更新值
		Table userTable = UserService.getInstance().getCacheUserDataTable();
		userTable.setValue(RedisUtil.genericKey(this.uid), "resource", toSFSObject().toJson());
		// 更新时间
		// lastUpdateTime = TimeUtil.getUtcNow().getMillis();
	}

	public ISFSObject toSFSObject() {
		ISFSObject ret = SFSObject.newInstance();
		ret.putLong(ResourceType.OIL.getValue(), this.oil);
		ret.putLong(ResourceType.STEEL.getValue(), this.steel);
		ret.putLong(ResourceType.ELEC.getValue(), this.elec);
		ret.putLong(ResourceType.CASH.getValue(), this.cash);
		ret.putLong(ResourceType.GOLD.getValue(), this.gold);
		return ret;
	}

	private boolean isInit() {
		com.itita.ww2.redis.cache.Table t = UserService.getInstance().getCacheUserDataTable();
		String data = t.getValue(RedisUtil.genericKey(userProfile.getUid()), "resource");
		return StringUtils.isNotBlank(data) && !data.equals("null");
	}

	/***
	 * 初始化数据
	 */
	public void initialize() {
		if (!isInit()) {
			ISFSObject config = PlayerConfig.getGameInitResource();
			this.oil = config.getInt(ResourceType.OIL.getValue());
			this.steel = config.getInt(ResourceType.STEEL.getValue());
			this.elec = config.getInt(ResourceType.ELEC.getValue());
			this.cash = config.getInt(ResourceType.CASH.getValue());
			this.gold = config.getInt(ResourceType.GOLD.getValue());
			this.update();
		} else {
			load();
		}
		userProfile.getUserInfo().addListener(this);
		userProfile.getRewardManager().addListener(new UserRewardImpl());
		updateResourceMax(userProfile.getUserInfo().getLevel());
	}

	@Override
	public void onUserLevelUp(int level) {
		updateResourceMax(level); // 更新一下资源最大值
	}

	class UserRewardImpl implements IUserRewardListener {

		@Override
		public Map<String, Object> onReward(RewardType type, ISFSObject params) throws Exception {
			Map<String, Object> ret = new HashMap<>();
			switch (type) {
			case MISSION_COMPLETE:
				ret = onMissionComplete(params.getBool("first"), params.getUtfString("missionId"));
				break;
			case CITY_SPECIAL_PRODUCT:
				ret = onCitySpecialProduct(params.getSFSObject("fixed_output"), params.getSFSObject("week_output"));
			case LOTTERY:
				ret = onLottery(params);
				break;
			case PAYMENT:
				ret = onPayment(params);
				break;
			case TIME_LIMIT_CARD:
				onTimeLimitCard(params);
				break;
			default:
				break;
			}
			return ret;
		}

		private void onTimeLimitCard(ISFSObject rewards) {
			for (String key : rewards.getKeys()) {
				CodeType type = CodeType.codeValueOf(key);
				if (type != null && type == CodeType.RESOURCE) {
					operRes(key, rewards.getInt(key));
				}
			}
			update();
			sync();
		}

		private Map<String, Object> onPayment(ISFSObject params) throws Exception {
			Map<String, Object> ref = new HashMap<>();
			// 
			String sku = params.getUtfString("sku");
			boolean first = params.getBool("first");
			// 
			JsonObject retObj = new JsonObject();
			Category category = PaymentConfig.getCategory(sku);
			switch (category) {
			case GOLD:
				int realCount = 0;
				if (first) {
					operRes(ResourceType.GOLD, PaymentConfig.getGoldFirstRewardBySKU(sku));
					realCount += PaymentConfig.getGoldCountBySKU(sku);
				}
				operRes(ResourceType.GOLD, PaymentConfig.getGoldCountBySKU(sku));
				realCount += PaymentConfig.getGoldCountBySKU(sku);
				retObj.addProperty(ResourceType.GOLD.getValue(), realCount);
				break;
			case PACK:
				{
					ISFSObject content = PaymentConfig.getPackItems(sku);
					for (String key : content.getKeys()) {
						CodeType type = CodeType.codeValueOf(key);
						if (type != null && type == CodeType.RESOURCE) {
							operRes(key, content.getInt(key));
							retObj.addProperty(key, content.getInt(key));
						}
					}
				}
				break;
			case MONTHLY_CARD:
				if (params.getBool("renewals")) {
					// 续费
					ISFSObject content = PaymentConfig.getRenewalsItems(sku);
					for (String key : content.getKeys()) {
						CodeType type = CodeType.codeValueOf(key);
						if (type != null && type == CodeType.RESOURCE) {
							operRes(key, content.getInt(key));
							retObj.addProperty(key, content.getInt(key));
						}
					}
				}
				break;
			default:
				break;
			}
			update();
			sync();
			if (retObj.size() > 0) {
				ref.put("res", retObj);
			}
			return ref;
		}

		private Map<String, Object> onLottery(ISFSObject lotteryItems) throws Exception {
			Map<String, Object> ret = new HashMap<>();
			for (String key : lotteryItems.getKeys()) {
				CodeType type = CodeType.codeValueOf(key);
				if (type != null && type == CodeType.RESOURCE) {
					operResWithCheck(key, lotteryItems.getInt(key));
				}
			}
			update();
			sync();
			return ret;
		}

		private Map<String, Object> onMissionComplete(boolean first, String missionId) throws Exception {
			Map<String, Object> ret = new HashMap<>();
			JsonObject retObj = new JsonObject();

			ISFSObject rewardObj = MissionConfig.getRewardComplete(missionId);
			for (String key : rewardObj.getKeys()) {
				CodeType type = CodeType.codeValueOf(key);
				if (type != null && type == CodeType.RESOURCE) {
					operResWithCheck(key, rewardObj.getInt(key));
					retObj.addProperty(key, rewardObj.getInt(key));
				}
			}
			if (first) {
				ISFSObject firstObj = rewardObj.getSFSObject("first");
				for (String key : firstObj.getKeys()) {
					operResWithCheck(key, firstObj.getInt(key));
				}
				// retObj.add("first", new JsonParser().parse(firstObj.toJson()));
			}
			ret.put("res", retObj);
			update();
			sync();
			return ret;
		}

		private Map<String, Object> onCitySpecialProduct(ISFSObject fixed_output, ISFSObject week_output)
				throws Exception {
			boolean needUpdateSync = false;
			for (String key : fixed_output.getKeys()) {
				CodeType type = CodeType.codeValueOf(key);
				if (type == CodeType.RESOURCE) {
					operResWithCheck(key, fixed_output.getInt(key));
					needUpdateSync = true;
				}
			}
			for (String key : week_output.getKeys()) {
				CodeType type = CodeType.codeValueOf(key);
				if (type == CodeType.RESOURCE) {
					operResWithCheck(key, week_output.getInt(key));
					needUpdateSync = true;
				}
			}
			if (needUpdateSync) {
				update();
				sync();
			}
			return null;
		}
	}
}
